// https://gitee.com/vtor3478/CharMove
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define SPACE_CHAR ' '
#define SEG_CNT  3
#define MAX_LEN 127

int strLen = 0;
int danceType = 0;
char userStrBuffer[MAX_LEN] = {"Written By Vtor3478~"};
char srcStrBuffer[] = {"DanceForYou!~"};
char showStrBuffer[MAX_LEN] = {0};
int charPos[MAX_LEN] = {0};
struct SegInfo{
    int start;
    int len;
    int end;
}segInfo[4];
                  //    0    1   2   3   4   5    6  7   8   9
int operateCnt[200] = {10,  30, 30, 10, 20, 30,  20, 6,  3,  3,
                       3,  3,  3,  20, 10, 200,100, 8,  5,  4 ,
                       3,   4,  10,  0};
int* operate = operateCnt;

void Init()
{
    int i = 0;
    int j = 0;
    int segIdx = 0;
    // 统计各个段的长度
    while ('\0' != userStrBuffer[i]) {
        if (SPACE_CHAR != userStrBuffer[i]) {
            ++segInfo[segIdx].len;
            ++strLen;
        } else {
            ++segIdx;
        }
        ++i;
    }
    segInfo[0].start = 0;
    for (segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
        segInfo[segIdx].end = segInfo[segIdx].start + segInfo[segIdx].len - 1;
        segInfo[segIdx + 1].start = segInfo[segIdx].end + 1;
    }
    for (i = 0; userStrBuffer[i] != '\0' ; ++i) {
        if (userStrBuffer[i] != SPACE_CHAR) {
            srcStrBuffer[j] = userStrBuffer[i];
            charPos[j] = j;
            ++j;
        }
    }
    operateCnt[7] *= strLen;
    operateCnt[8] *= strLen;
    operateCnt[9] *= strLen;
    operateCnt[10] *= strLen;
    operateCnt[11] *= strLen;
    operateCnt[12] *= strLen;
    operateCnt[14] *= strLen;
    operateCnt[17] *= strLen;
    operateCnt[18] *= strLen;
    operateCnt[19] *= strLen;
    operateCnt[20] *= strLen;
    operateCnt[21] *= strLen;
}
void UpdateBuffer()
{
    int idx = 0;
    memset(showStrBuffer,SPACE_CHAR,MAX_LEN);
    showStrBuffer[MAX_LEN - 1] = '\0';

    for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
        int startIdx = segInfo[segIdx].start;
        int endIdx = segInfo[segIdx].end;
        for (idx = startIdx; idx <= endIdx; ++idx) {
            if (charPos[idx] < 0) {
                break;
            }
            showStrBuffer[charPos[idx]] = srcStrBuffer[idx];
        }
    }
}
void Circle(int startIdx, int endIdx)
{
    int endPos = charPos[endIdx];
    for (int charIdx = endIdx; charIdx >= startIdx; --charIdx) {
        charPos[charIdx] = charPos[charIdx - 1];
    }
    charPos[startIdx] = endPos;
}
void Stepper(int startIdx, int endIdx, int step)
{
    for (int charIdx = endIdx; charIdx >= startIdx; --charIdx) {
        charPos[charIdx] += step;
    }
}
void Rand(int startIdx, int endIdx, int minPos ,int maxPos, int step)
{
    for (int charIdx = endIdx; charIdx >= startIdx; --charIdx) {
        int dir = rand() % 2;
        dir -= 1;
        charPos[charIdx] += dir * step;
        if (charPos[charIdx] < minPos) {
            charPos[charIdx] = maxPos;
        }
        if (charPos[charIdx] > maxPos) {
            charPos[charIdx] = minPos;
        }
    }
}
void Swing(int startIdx, int endIdx, int range)
{
    static int dir = 1;
    static int dis = 0;
    Stepper(startIdx, endIdx, dir);
    ++dis;
    if (1 == dir) {
        if (dis > range) {
            dir = -1;
            dis = 0;
        }
    }
    if (-1 == dir) {
        if (dis > 2 * range) {
            dir = 1;
            dis = 0;
        }
    }
}

void UserOperate()
{
    static int cnt = -1;
    ++cnt;
    if (*operate == 0) {
        return ;
    }
    if (cnt == *operate) {
        ++ operate;
        cnt = 0;
        ++ danceType;
    }
    if(0 == danceType) { // just for test
    }
    if(1 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, 1);
        }
    }
    if (2 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, -1);
        }
    }
    if (3 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, 1);
        }
    }
    if (4 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, segIdx + 1);
        }

    }
    if (5 == danceType) {
    }
    if (6 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, -(segIdx + 1));
        }
    }
    if (7 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 2 == 0) {
        Circle(startIdx,endIdx);
        }
    }
    if (8 == danceType) {
        int segIdx = 2;
        int endIdx = segInfo[segIdx].end;
        int startIdx = segInfo[segIdx].start;
        Stepper(startIdx,endIdx,1);
    }
    if (9 == danceType) {
        int segIdx = 1;
        int endIdx = segInfo[segIdx].end;
        int startIdx = segInfo[segIdx].start;
        Stepper(startIdx,endIdx,1);
    }
    if (10 == danceType) {
        int segIdx = 1;
        int startIdx = segInfo[segIdx].start;
        int endIdx = segInfo[2].end;
        Stepper(startIdx,endIdx,-1);

    }
    if (11 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[segIdx].end;
        int endIdx = segInfo[segIdx].end;
        startIdx = startIdx - cnt / 3;
        Stepper(startIdx,endIdx,1);
    }
    if (12 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        endIdx = endIdx - cnt / 3;
        Stepper(startIdx,endIdx,1);
    }
    if (13 == danceType) {
        for (int segIdx = 0; segIdx < SEG_CNT; ++segIdx) {
            int startIdx = segInfo[segIdx].start;
            int endIdx = segInfo[segIdx].end;
            Stepper(startIdx, endIdx, -1);
        }
    }
    if (14 == danceType) {
        int segIdx = 1;
        int startIdx = segInfo[segIdx].start;
        int endIdx = segInfo[segIdx].end;
        startIdx = endIdx = cnt / 10;
        if (cnt % 10 < 5) {
            Stepper(startIdx, endIdx, -1);
        }
    }
    if (15 == danceType) {
        int segIdx = 0;
        int step = 1;
        int startIdx = segInfo[segIdx].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 80 < 20 || cnt % 80 >= 60) {
            step = -1;
        }
        Stepper(startIdx, endIdx, step);

        startIdx = endIdx + 1;
        segIdx = 2;
        step = 1;
        startIdx = segInfo[segIdx].start;
        endIdx = segInfo[segIdx].end;
        if (cnt % 80 >= 20 && cnt % 80 < 60) {
            step = -1;
        }
        Stepper(startIdx, endIdx, step);
    }
    if (16 == danceType) {
        int segIdx = 2;
        int step = 1;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 40 < 10 || cnt % 40 >= 30) {
            step = -1;
        }
        Stepper(startIdx, endIdx, step);
    }
    if (17 == danceType) {
        int segIdx = 2;
        int step = 0;
        static int oldStep = 0;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        step = sin(cnt / 5.0f) * 20;
        Stepper(startIdx, endIdx, step - oldStep);
        oldStep = step;
    }
    if (18 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        Circle(startIdx,endIdx);
    }
    if (19 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 2 == 0) {
            Circle(startIdx,endIdx);
        }
    }
    if (20 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 3 == 0) {
            Circle(startIdx,endIdx);
        }
    }
    if (21 == danceType) {
        int segIdx = 2;
        int startIdx = segInfo[0].start;
        int endIdx = segInfo[segIdx].end;
        if (cnt % 4 == 0) {
            Circle(startIdx,endIdx);
        }
    }

}

void Show()
{
    static int cnt = 0;
    while(0 != operateCnt[danceType]) {
        UserOperate();
        UpdateBuffer();
        printf("%s\r\n",(char*)showStrBuffer);
//        printf("%04d,%04d:%s\r\n",cnt,danceType,(char*)showStrBuffer);
        ++cnt;
    }
}

int main()
{
    Init();
    Show();
    return 0;
}
